package com.ruyuan.eshop.diplomacy.manager.common.db;

import com.alibaba.nacos.common.utils.MapUtils;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.ruyuan.eshop.diplomacy.domain.dao.DiplomacyDAO;
import com.ruyuan.eshop.diplomacy.manager.common.cache.RedisSetCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.ruyuan.eshop.common.constants.diplomacy.BaseConstants.LONG_FIVE_MINUTES;
import static com.ruyuan.eshop.common.utils.diplomacy.NumberUtils.getInteger;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;


/**
 * redis(set)数据源抽象类
 *
 * @author zhonghuashishan
 */
@Slf4j
public abstract class AbstractRedisSetDatabase<T> implements RedisSetDatabase<T> {

    @Resource
    private DiplomacyDAO diplomacyDAO;

    /**
     * 5分钟内单表变更数据主键ID集合
     *
     * @param tableName
     * @return java.util.Optional<java.util.Set<java.lang.Integer>>
     * @author zhonghuashishan
     */
    private Optional<Set<Integer>> getSingleTableUpdateIdSet(String tableName) {
        // 获取最近5分钟时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String beforeDate = simpleDateFormat.format(new Date(System.currentTimeMillis() - LONG_FIVE_MINUTES));

        // 获取sql
        String sql = "SELECT ID FROM " + tableName + " WHERE UPDATE_TIME>'" + beforeDate + "'";
        List<Map<String, Object>> mapList = diplomacyDAO.select(sql);
        if (CollectionUtils.isEmpty(mapList)) {
            return Optional.empty();
        }
        Set<Integer> idSet = mapList.stream().map(fieldMap -> Integer.parseInt(String.valueOf(fieldMap.get("ID")))).collect(toSet());
        return Optional.of(idSet);
    }

    /**
     * 获取全量数据
     *
     * @param tableName 表名
     * @return java.util.Optional<java.util.Map<java.lang.String,com.ruyuan.eshop.diplomacy.manager.common.source.RedisSetSource>>
     * @author zhonghuashishan
     */
    @Override
    public Optional<Map<String, RedisSetCache>> listIncrMap(String tableName) {
        Optional<Set<Integer>> idSetOpt = getSingleTableUpdateIdSet(tableName);
        if (!idSetOpt.isPresent()) {
            return Optional.empty();
        }
        return listIncrMap(tableName, idSetOpt.get());
    }
    
    /**
     * 批量获取需要添加和删除的Map
     *
     * @return java.util.Optional<java.util.Map<java.lang.String,com.ruyuan.eshop.diplomacy.manager.common.source.RedisSetSource>> key redis key，value 资源对象
     * @author zhonghuashishan
     */
    @Override
    public Optional<Map<String, RedisSetCache>> listAllRedisKeyMap() {
        Optional<List<Integer>> allIdListOpt = getTableAllIdList();
        if (!allIdListOpt.isPresent()) {
            return Optional.empty();
        }

        Optional<Map<String, RedisSetCache>> setSourceMapOpt = listIncrMap(getTableName(), Sets.newHashSet(allIdListOpt.get()));
        if (!setSourceMapOpt.isPresent()) {
            return Optional.empty();
        }
        Map<String, RedisSetCache> resultMap = Maps.newHashMap();
        for (Map.Entry<String, RedisSetCache> entry : setSourceMapOpt.get().entrySet()) {
            String key = entry.getKey();
            Set<String> addSet = entry.getValue().getAddSet();
            Set<String> deleteSet = entry.getValue().getDeleteSet();
            if (!resultMap.containsKey(key)) {
                RedisSetCache redisSetCache = new RedisSetCache();
                resultMap.put(key, redisSetCache);
            }
            resultMap.get(key).getAddSet().addAll(addSet);
            resultMap.get(key).getDeleteSet().addAll(deleteSet);
        }

        return MapUtils.isEmpty(resultMap) ? Optional.empty() : Optional.of(resultMap);
    }

    /**
     * 获取单表所有主键ID集合
     *
     * @return java.util.Optional<java.util.List<java.lang.Integer>>
     * @author zhonghuashishan
     */
    @Override
    public Optional<List<Integer>> getTableAllIdList() {
        String sql = "SELECT ID FROM " + getTableName();
        List<Map<String, Object>> mapList = diplomacyDAO.select(sql);
        if (CollectionUtils.isEmpty(mapList)) {
            return Optional.empty();
        }
        List<Integer> idSet = mapList.stream().map(fieldMap -> getInteger(fieldMap.get("id"))).collect(toList());
        return Optional.of(idSet);
    }

}
